# -*- coding: binary -*-

# Module with Splunk login related methods
module Msf::Exploit::Remote::HTTP::Splunk::Login
  # performs a splunk login
  #
  # @param username [String] Username
  # @param password [String] Password
  # @param timeout [Integer] The maximum number of seconds to wait before the request times out
  # @return [String,nil] the session cookies as a single string on successful login, nil otherwise
  def splunk_login(username, password, timeout = 20)
    # gets cval cookies
    cookie = splunk_helper_extract_token(timeout)
    if cookie.nil?
      vprint_error('Unable to extract login tokens')
      return nil
    end

    cval_value = cookie.match(/cval=([^;]*)/)[1]
    # login post, should get back the splunkd_port and splunkweb_csrf_token_port cookies
    res = send_request_cgi({
      'uri' => splunk_url_login,
      'method' => 'POST',
      'cookie' => cookie,
      'vars_post' =>
        {
          'username' => username,
          'password' => password,
          'cval' => cval_value
        }
    }, timeout)

    unless res
      vprint_error("FAILED LOGIN. '#{username}' : '#{password}' returned no response")
      return nil
    end

    unless res.code == 303 || (res.code == 200 && res.body.to_s.index('{"status":0}'))
      vprint_error("FAILED LOGIN. '#{username}' : '#{password}' with code #{res.code}")
      return nil
    end

    print_good("SUCCESSFUL LOGIN. '#{username}' : '#{password}'")
    return cookie << " #{res.get_cookies}"
  end

  # The free version of Splunk does not require authentication. Instead, it'll log the
  # user right in as 'admin'. If that's the case, no point to brute-force, either.
  #
  # @return [Boolean] true if auth is required, false otherwise
  def splunk_is_auth_required?
    cookie = splunk_helper_extract_token
    res = send_request_raw({
      'uri' => splunk_home,
      'cookie' => cookie
    })

    !(res && res.body =~ /Logged in as (.+)/)
  end

  # Return the default credentials if found
  #
  # @return [Array, nil] username, password if found, nil otherwise
  def splunk_default_creds
    p = %r{Splunk's default credentials are </p><p>username: <span>(.+)</span><br />password: <span>(.+)</span>}
    res = send_request_raw({ 'uri' => target_uri.path })
    user, pass = res.body.scan(p).flatten
    return [user, pass] if user && pass
  end

  # Extract and test the default credentials, if found
  #
  # @return [String, nil] the session cookies as a single string on successful login, nil otherwise
  def splunk_login_with_default_creds
    user, pass = splunk_default_creds
    splunk_login(user, pass) if user && pass
  end
end
